var GFFunctionalInterpreterException = Base.extend({
	errmsg: null,
	code: null,
	pointer: null,
	constructor: function(errmsg,code,p)
	{
		this.errmsg = errmsg;
		this.code = code;
		this.pointer = p;
	}
});

var GFFunctionalInterpreter = Base.extend({
	current_code: null,
	current_pointer: null,
	current_functional: null,
	breaking: false,
	running: false,

	msgout_fun: null,

	constructor: function()
	{
		this.Reset();
	},
	Reset: function()
	{
		this.stack = new Array();
		this.current_code = '';
		this.current_pointer = 0;
		this.current_functional = GFFunctionalInterpreter.CreateJSFunctional(true);
		this.msgout_fun = null;
		this.breaking = false;
		this.running = false;
	},
	AppendCode: function(code)
	{
		this.current_code += code;
	},
	msgout: function(msg)
	{
		if(this.msgout_fun) this.msgout_fun(msg);
	},
	eval_functional: function(str)
	{
		var fun;
		var tmp;

		fun = GFFunctionalInterpreter.LookupFunctional(str);
		if(!fun) {
			throw new GFFunctionalInterpreterException("Functional \""+str+"\" not found.",this.current_code,this.current_pointer);
		}
		else {
			fun._this = this;
			Debug.trace(3,'GownFullInterpreter: is evaluating %s',str);
			tmp = fun(this.current_functional);
			if(tmp instanceof Function) {
				this.current_functional = tmp;
				return true;
			}
			else return false; // this is a break code functional
		}
	},
	EvaluateNext: function()
	{
		var i,ch;
		var quotep,quotes,escapep;
		var buf;
		var bb;
		var ret;

		quotep = false;
		escapep = false;
		bfor = false;
		buf = '';
		quotes = '';
		bb = false;
		for(i=0;i<this.current_code.length && !bfor;i++) {
			ch = this.current_code.charAt(i);
			this.current_pointer = i;
			switch(ch) {
			case '"':
				if(quotep) {
					if(escapep) { quotes += '"'; escapep = false; }
					else {
						var jsobj;
						quotep = false;
						jsobj = String(quotes);
						this.current_functional = GFFunctionalInterpreter.CreateJSFunctional(jsobj,this.current_functional);
					}
				}
				else {
					quotep = true;
					quotes = '';
				}
				break;
			case "\\":
				if(quotep) {
					if(escapep) {
						escapep = false;
						quotes += "\\";
					}
					else escapep = true;
				}
				else buf += ch;
				break;
			case ':':
				if(quotep) {
					buf += ch;
					escapep = false;
				}
				else {
					bb = true;
					if(buf) {
						// check buf...
						bb = this.eval_functional(buf);
						bfor = true;
						buf = '';
					}
				}
				break;
			default:
				escapep = false;
				if(quotep) quotes += ch;
				else buf += ch;
			}
		}
		if(bfor) { // truncate the code
			this.current_code = this.current_code.substr(i);
			this.current_pointer = 0;
			ret = true;
		}
		else { // EOF or errors
			if(quotep) throw new GFCommandInterpreterException("Missing terminating \" character",this.current_code,this.current_pointer);
			bb = true;
			if(buf) {
				// run the last code
				bb = this.eval_functional(buf);
				this.current_code = '';
				this.current_pointer = 0;
			}
			ret = false;
		}
		if(bb) return ret;
		else { // Break code
			this.breaking = true;
			throw { breakcode: true };
		}
	},
	Run: function()
	{
		var b;

		if(this.breaking) return false;
		if(this.running) return false;

		try {
			this.running = true;
			b = true;
			while(b) b = this.EvaluateNext();
		}
		catch(e) {
			if(e.breakcode) return false; // break code

			this.running = false;
			this.current_code = '';
			this.current_pointer = 0;
			if (e.errmsg) this.msgout("Exception: " + e.errmsg);
			else throw e;
		}
		this.running = false;

		return this.current_functional;
	},
	Continue: function(fun)
	{
		if(!this.breaking) return false;
		this.current_functional = fun;
		this.breaking = false;
		this.running = false;
		return this.Run();
	}
},
{
	functional_table: null,
	fun_s: null,
	fun_k: null,
	fun_i: null,

	init: function()
	{
		this.functional_table = {};
//		this.RegisterFunctional('_k', function(x) { return function(y) { return x; } });
//		this.RegisterFunctional('_s', function(x) { return function(y) { return function(z) { return (x(z))(y(z)); } }});
//		this.RegisterFunctional('_i', function(x) { return x; });
		this.RegisterFunctional('void',function(x) { return (function(y){return y;}); });
		this.RegisterFunctional('break',function(x) { return false; });
	},
	RegisterFunctional: function(name,fun)
	{
		if(this.functional_table[name]) return false;
		else {
			this.functional_table[name] = fun;
			return true;
		}
	},
	UnregisterFunctional: function(name)
	{
		this.functional_table[name] = null;
		delete this.functional_table[name];
		return true;
	},
	LookupFunctional: function(name)
	{
		if(this.functional_table[name]) return this.functional_table[name];
		else return false;
	},
	CreateJSFunctional: function(jsobj,constant)
	{
		return function(x) { return x ? (constant ? constant : (function(y){return y;})) : jsobj; }
	}
});

